<template>
    <div class="chat" ref="ServiceChat">
        <ChatWindow
            v-draggable
            :message-list="state.messageList"
            :maxLength="userInfo.maxLength"
            @close="close"
            @download="download"
            @message-click="messageClick"
            @tabs-click="tabsClick"
            @connectService="connectService"
            @reConnect="reConnect"
            @replyClick="replyClick"
            @refresh="refresh"
            @toTicket="toTicket"
            @zoom="zoom"
            @sendMessage="sendMessage"
        >
        </ChatWindow>

        <transition name="el-fade-in-linear">
            <div class="tips-box" v-if="state.showTips">
                <div class="tips">
                    <Close class="close" size="20" @click="state.showTips = false" />

                    <div class="title">Tip</div>

                    <div>{{ userInfo.nonworkingMsgWeb }}</div>

                    <el-button type="primary" class="btn" @click="state.showTips = false">
                        OK
                    </el-button>
                </div>
            </div>
        </transition>

        <transition name="el-fade-in-linear">
            <TicketForm
                v-draggable
                v-if="state.showForm"
                @close="state.showForm = false"
                @success="formSuccess"
                :userId="userInfo.userId"
                :countryList="countryList"
            ></TicketForm>
        </transition>

        <transition name="el-fade-in-linear">
            <Evaluate
                v-if="state.showEvaluate"
                @close="state.showEvaluate = false"
                @evaluate="evaluate"
            ></Evaluate>
        </transition>
    </div>
</template>

<script setup>
import { submitEvaluate, upload, replyList, firstCategory, addReplyHit } from '@/api'
import userAvatar from '@/assets/chat-tx.png'
import { reactive, onMounted, onBeforeUnmount, nextTick, computed, watch, ref, provide } from 'vue'
import axios from 'axios'
import { EventSourcePolyfill } from 'event-source-polyfill'
import io from 'socket.io-client'
import ChatWindow from '@/components/ServiceChat/ChatWindow.vue'
import TicketForm from '@/components/TicketForm/TicketForm.vue'
import Evaluate from '@/components/Evaluate/Evaluate.vue'
import moment from 'moment'
import { ElMessage } from 'element-plus'
import { saveAs } from 'file-saver'
import screenfull from 'screenfull'
// import { useReplyStore } from '@/store/index'

import { Close } from '@element-plus/icons-vue'

const props = defineProps({
    userInfo: {
        type: Object,
        default: () => {},
    },
    countryList: {
        type: Array,
        default: () => {
            return []
        },
    },
})

const emits = defineEmits(['close'])

const ServiceChat = ref()

const state = reactive({
    serviceInfo: {
        id: '',
        name: '',
        avatar: '',
    },
    messageList: [
        {
            author: 'support',
            type: 'text',
            id: 1,
            meta: moment().format('HH:mm'),
            data: {
                text: 'Hi,  I am your virtual assistant. To get started just click on the button below to fill in the information first, and then connect to the Manual Service.',
            },

            showTabs: false,
        },
    ],
    category: [],
    replyMap: {},
    replyPageMap: {},
    replyCount: {},
    agentServiceId: '',
    showTypingIndicator: '',
    alwaysScrollToBottom: false,
    messageStyling: true,
    showForm: false,
    showEvaluate: false,
    socket: null,
    userInfo: {},
    isOnline: false,
    showTips: false,
    hasService: false,
    formId: '',
})

onMounted(() => {
    fetchCategory()
})

onBeforeUnmount(() => {})

watch(
    () => props.userInfo,
    (newValue) => {
        state.serviceInfo.avatar = newValue.agentAvatar
        state.serviceInfo.name = newValue.agentDefaultName
        state.messageList[0].data.text = newValue.workingMsg
        state.messageList[0].avatar = state.serviceInfo.avatar
        state.messageList[0].name = state.serviceInfo.name

        if (newValue.enableQuick) {
            state.messageList[0].showTabs = true
        }
    },
    { deep: true }
)

const categoryData = () => {
    return {
        category: computed(() => state.category),
    }
}

provide('category', categoryData)

const relpyData = () => {
    return {
        reply: computed(() => state.replyMap),
        replyCount: computed(() => state.replyCount),
    }
}

provide('reply', relpyData)

const iconDisabledData = () => {
    return {
        disabled: computed(() => !state.isOnline),
    }
}

provide('iconDisabled', iconDisabledData)

const inputDisabledData = () => {
    return {
        disabled: computed(() => !props.userInfo.enableQuick && !state.isOnline),
    }
}

provide('inputDisabled', inputDisabledData)

const formSuccess = (id) => {
    state.formId = id
    createSocket()
    online()
}

const online = async () => {
    const { sessionId, traceId, client, appId, userId } = props.userInfo

    const sourceUrl = `${
        import.meta.env.VITE_SOCKET
    }/witek-contact/im/online?userId=${userId}&sessionId=${sessionId}&traceId=${traceId}&client=${client}&appId=${appId}`

    const source = new EventSourcePolyfill(sourceUrl, {
        //重连时间间隔，单位：毫秒，默认45000毫秒，这里设置为10分钟
        heartbeatTimeout: 10 * 60 * 1000,
    })

    source.onopen = () => {
        console.log('NOTICE建立连接')
    }

    source.onerror = (e) => {
        if (e.readyState == EventSource.CLOSED) {
            console.log('NOTICE连接关闭')
        } else if (source.readyState == EventSource.CONNECTING) {
            console.log('NOTICE正在重连')
            //重新设置header
        } else {
            console.log(e)
        }
    }

    return
}

const fetchCategory = () => {
    firstCategory().then((res) => {
        const data = res.data
        data.sort((a, b) => a.orderNum - b.orderNum)
        state.category = data
    })
}

const fetchReplyList = async ({ msgId, id, query }, isRefresh) => {
    const params = {
        page: state.replyPageMap[msgId],
        size: 5,
        queryData: {
            categoryId: id,
            query,
        },
    }

    const res = await replyList(params)

    if (res.data) {
        if (query && res.data.length === 1 && !isRefresh) {
            //刷新的时候不作处理
            //query存在代表是发送信息时触发查询，且只有一条数据则直接当成消息回复

            addReplyHit(res.data[0].id)
            createReplyMessage(res.data[0])
        } else {
            state.replyMap[msgId] = res.data
        }

        state.replyCount[msgId] = res.count
    } else {
        state.replyMap[msgId] = res.msg
    }

    if ((params.page + 1) * params.size >= res.count) {
        state.replyPageMap[msgId] = -1
    }
}

const createSocket = () => {
    const data = props.userInfo

    // const socket = io(`${import.meta.env.VITE_SOCKET}:${data.port}/user`, {
    const socket = io(`${import.meta.env.VITE_SOCKET}/user`, {
        // const socket = io(`http://localhost:3000`, {
        // 指定传输协议为websocket
        transports: ['websocket'],
        // 附加到连接URL的查询参数
        query: {
            userId: data.userId,
            session: data.sessionId,
            traceId: data.traceId,
            appId: data.appId, // 确保appId已定义
            formId: state.formId,
        },
    })

    // 接下来，你可以添加事件监听器来处理socket连接的各种事件，例如：
    socket.on('connect', () => {
        console.log('Socket connected!')
    })

    socket.on('message', (data) => {
        if (data.callType === 'chat_in') {
            console.log('自己发送的消息:', data)
            const message = state.messageList.find((e) => e.id === data.msgId)
            if (message) {
                message.status = 'success'
            }
        } else {
            console.log('收到的消息-message:', data)

            const type = data.msgType === 'text' ? 'text' : 'file'

            const message = {
                author: 'support',
                type: type,
                avatar: state.serviceInfo.avatar,
                name: state.serviceInfo.name,
                id: state.messageList.length, // or text '1'
                meta: moment().format('HH:mm'),
                data: {},
            }

            const initMessage = {
                text: () => {
                    return {
                        ...message,
                        data: {
                            text: data.message,
                        },
                    }
                },
                file: () => {
                    const typeIndex = data.fileName.lastIndexOf('.')

                    return {
                        ...message,
                        data: {
                            file: {
                                name: data.fileName,
                                url: data.fileUrl,
                                title: data.msgType === 'cooperation' ? data.message : '',
                                size: data.fileSize,
                                extension: data.fileName.substring(typeIndex + 1),
                                width: data.fileWidth,
                                height: data.fileHeight,
                            },
                        },
                    }
                },
            }

            state.messageList = [...state.messageList, initMessage[type]()]
            console.log(state.messageList)

            scrollToBottom()
        }
    })

    socket.on('new', (data) => {
        console.log('接收到的消息-new:', data)
    })

    socket.on('status', (data) => {
        console.log('接收到的消息-status:', data)
        if (data.noAgent) {
        } else {
            if (data.agentServiceId) {
                state.serviceInfo.id = data.agentServiceId
                state.agentServiceId = data.agentServiceId
            }

            if (data.agentName) {
                state.serviceInfo.name = data.agentName
            }

            state.isOnline = true
        }

        const systemArr = ['transout', 'status', 'end', 'error', 'new']

        if (systemArr.includes(data.msgType) && data.messageType === 'text') {
            state.messageList = [
                ...state.messageList,
                {
                    type: 'system',
                    meta: moment().format('HH:mm'),
                    data: {
                        text: data.message,
                    },
                },
            ]
        }

        if (data.msgType === 'satisfaction') {
            state.messageList = [
                ...state.messageList,
                {
                    author: 'support',
                    type: 'text',
                    id: 1,
                    avatar: state.serviceInfo.avatar,
                    meta: moment().format('HH:mm'),
                    data: {
                        text: 'Please comment on this service to help us improve.',
                    },
                    hasBtn: true,
                    btnText: 'Service Feedback',
                    btnType: 'evaluate',
                },
            ]
        }
    })

    socket.on('disconnect', (reason) => {
        console.log('Disconnected from server due to:', reason)
        state.messageList = [
            ...state.messageList,
            {
                type: 'system',
                meta: moment().format('HH:mm'),
                data: {
                    text: 'The chat has been disconnected. Please click',
                },
                hasBtn: true,
                btnText: 'Re-connect',
                btnType: 'connect',
            },
        ]
    })

    socket.on('error', (error) => {
        console.error('Socket error:', error)
    })

    socket.on('connect_error', (error) => {
        console.error('Connection error:', error)
    })

    socket.on('pong', (latency) => {
        console.log('Pong received, latency:', latency)
    })

    state.socket = socket

    // 其他逻辑代码...
}

const uploadFile = async (file, msgId, index) => {
    const data = props.userInfo

    try {
        // 创建 FormData 对象
        const formData = new FormData()

        // 将 Blob 对象添加到 FormData 中，指定文件名
        formData.append(
            'file',
            new File([file.blob], `${file.name}.${file.extension}`),
            `${file.name}.${file.extension}`
        )
        // formData.append('userId', data.userId)
        // formData.append('appId', data.appId)
        // formData.append('channel', 'webim')

        // 发起 POST 请求，并添加上传进度处理
        const config = {
            headers: {
                'Content-Type': 'multipart/form-data',
            },
            onUploadProgress: (progressEvent) => {
                // 计算进度百分比
                const percentCompleted = Math.round(
                    (progressEvent.loaded * 100) / progressEvent.total
                )
                console.log(`Upload Progress: ${percentCompleted}%`)

                state.messageList[index].data.file.progress = percentCompleted

                // 这里可以根据需要处理进度，比如更新UI进度条
                // updateProgressBar(percentCompleted);
            },
        }

        const res = await axios.post(
            `${import.meta.env.VITE_SERVE}/resource/oss/uploadByUser`,
            formData,
            config
        )

        if (res.data.code === 200) {
            state.messageList[index].data.file.url = res.data.data.url

            const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'tiff']

            upload({
                paste: false,
                title: `${file.name}.${file.extension}`,
                fileLength: file.size,
                fileType: file.extension,
                url: res.data.data.url,
                image: imageExtensions.includes(file.extension),
                fileWidth: file.width,
                fileHeight: file.height,
                duration: parseInt(file.duration * 1000),
                userId: data.userId,
                msgId,
            })
            // state.messageList[index].data.file.progress = 100
        } else {
            const message = state.messageList.find((e) => e.id === msgId)
            if (message && message.status === 'loading') {
                message.status = 'fail'
            }
        }

        // 处理响应
    } catch (error) {
        console.error(error)
        // 处理错误
    }
}

const sendMessage = (message) => {
    const data = props.userInfo
    const { file } = message.data
    const msgId = createUuid()

    if (!state.isOnline && data.enableQuick) {
        //未连接
        state.messageList = [
            ...state.messageList,
            {
                ...message,
                id: msgId,
                avatar: userAvatar,
                meta: moment().format('HH:mm'),
                status: 'success',
            },
        ]

        getReply(message.data.text)
    } else {
        //已连接
        state.messageList = [
            ...state.messageList,
            {
                ...message,
                id: msgId,
                avatar: userAvatar,
                meta: moment().format('HH:mm'),
                status: 'loading',
            },
        ]

        if (file) {
            uploadFile(file, msgId, state.messageList.length - 1)
        } else {
            const text = message.type == 'emoji' ? message.data.emoji : message.data.text
            message.type ==
                state.socket.emit('message', {
                    appId: data.appId,
                    userId: data.userId,
                    type: 'message',
                    msgType: file ? 'file' : 'text',
                    sessionId: data.sessionId,
                    message: text,
                    msgId,
                })

            setTimeout(() => {
                const message = state.messageList.find((e) => e.id === msgId)
                if (message && message.status === 'loading') {
                    message.status = 'fail'
                }
            }, 5000)
        }
    }

    scrollToBottom()
}

const getReply = async (val) => {
    const msgId = createUuid()
    state.replyPageMap[msgId] = 0

    await fetchReplyList({
        msgId,
        query: val,
    })

    if (state.replyMap[msgId]) {
        state.messageList = [
            ...state.messageList,
            {
                id: msgId,
                query: val,
                author: 'support',
                type: 'reply',
                meta: moment().format('HH:mm'),
                avatar: state.serviceInfo.avatar,
                name: state.serviceInfo.name,
            },
        ]
    }
}

const reConnect = () => {
    state.socket.disconnect()
    state.socket = null
    createSocket()
}

const evaluate = (data) => {
    submitEvaluate({
        satisLevel: data.rate,
        satisComment: data.textarea,
        id: state.serviceInfo.id,
    }).then((res) => {
        ElMessage.success('send successfully!')
        state.showEvaluate = false
    })
}

const messageClick = (type) => {
    if (type === 'evaluate') state.showEvaluate = true
}

const createReplyMessage = (data) => {
    const type = data.replyType === 0 ? 'text' : 'file'

    const message = {
        author: 'support',
        type: type,
        avatar: state.serviceInfo.avatar,
        name: state.serviceInfo.name,
        id: createUuid(), // or text '1'
        meta: moment().format('HH:mm'),
    }

    const init = {
        text: () => {
            state.messageList = [
                ...state.messageList,
                {
                    ...message,
                    data: {
                        text: data.replyContent,
                    },
                },
            ]
        },
        file: () => {
            data.fileList.map((file) => {
                const typeIndex = file.title.lastIndexOf('.')
                const extension = file.title.substring(typeIndex + 1)

                state.messageList = [
                    ...state.messageList,
                    {
                        ...message,
                        data: {
                            file: {
                                ...file,
                                width: file.fileWidth,
                                height: file.fileHeight,
                                title: data.title,
                                name: file.title,
                                size: file.fileLength,
                                extension,
                            },
                        },
                    },
                ]
            })
        },
    }

    init[type]()
}

const replyClick = (val) => {
    state.messageList = [
        ...state.messageList,
        {
            author: 'me',
            type: 'text',
            avatar: userAvatar,
            id: createUuid(), // or text '1'
            meta: moment().format('HH:mm'),
            data: {
                text: val.title,
            },
        },
    ]

    addReplyHit(val.id)

    setTimeout(() => {
        createReplyMessage(val)
    }, 500)
}

const connectService = () => {
    if (props.userInfo.isWorkingHours) {
        if (!state.socket) {
            state.showForm = true
        } else {
            ElMessage.warning(
                'The form information has been submitted and is currently in a chat. No more commits.'
            )
        }
    } else {
        state.showTips = true
    }
}

const tabsClick = async (id) => {
    const msgId = createUuid()
    state.replyPageMap[msgId] = 0

    await fetchReplyList({
        msgId,
        id,
    })

    state.messageList = [
        ...state.messageList,
        {
            id: msgId,
            categoryId: id,
            author: 'support',
            type: 'reply',
            meta: moment().format('HH:mm'),
            avatar: state.serviceInfo.avatar,
            name: state.serviceInfo.name,
        },
    ]
}

const refresh = async (data) => {
    const msgId = data.msgId
    state.replyPageMap[msgId]++
    await fetchReplyList(data, true)
}

const scrollToBottom = async () => {
    nextTick(() => {
        const messageList = document.getElementsByClassName('sc-message-list')[0]
        if (messageList) {
            const lastMessage = messageList.lastElementChild
            if (lastMessage) {
                lastMessage.scrollIntoView({ behavior: 'smooth', block: 'end' })
            }
        }
    })
}

const download = async (file) => {
    try {
        const res = await axios.get(file.url, {
            responseType: 'blob',
        })

        const blob = new Blob([res.data], {
            type: 'application/octet-stream',
        })
        saveAs(blob, file.name)
    } catch (error) {
        ElMessage.error('下载失败，请联系管理员!')
    }
}

const close = () => {
    emits('close')
    state.showForm = false
}

const zoom = (val) => {
    screenfull.toggle(ServiceChat.value)
}

const createUuid = () => {
    const data = props.userInfo

    // 获取当前时间的时间戳
    const timestamp = Date.now()

    // 生成一个四位的随机数
    const randomNum = Math.floor(1000 + Math.random() * 9000)

    // 返回拼接后的时间戳加随机数
    return `2_${data.userId}_${timestamp}_${randomNum}`
}

const toTicket = () => {
    window.open(import.meta.env.VITE_TICKET)
}
</script>

<style scoped lang="scss">
.chat {
    width: 880px;
    height: 80vh;
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 99;
    .tips-box {
        position: absolute;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        z-index: 99;
        border-radius: 8px;
        background: rgba(0, 0, 0, 0.3);
        font-size: 16px;
        color: #333333;

        .tips {
            font-size: 16px;
            color: #333333;
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            width: 394px;
            background: #ffffff;
            border-radius: 4px;
            padding: 30px 18px;
            box-sizing: border-box;
            display: flex;
            flex-direction: column;
            align-items: center;

            .title {
                font-size: 24px;
                color: #333333;
                font-weight: bold;
                margin-bottom: 24px;
            }

            .btn {
                width: 100px;
                min-height: 40px;
                margin-top: 40px;
            }

            .close {
                cursor: pointer;
                position: absolute;
                right: 10px;
                top: 10px;
                width: 28px;
                height: 28px;
                color: #999999;
            }
        }
    }
}
</style>
